#include "TimerManager.h"

TimerManager::TimerManager(boost::asio::io_service * pIO)
{
    m_global_timer_id = 1;
	m_pIOService = pIO;
}

TimerManager::~TimerManager()
{
    stop();
}

TimerID TimerManager::schedule(TimerID tCurID, uint32_t duration, const OnTimer & handler)
{
	if (!handler || m_pIOService == NULL)
	{
		return 0;
	}

	if (tCurID == 0)
	{
		tCurID = m_global_timer_id;
		m_global_timer_id++;
		add_timer(tCurID, duration, handler);
	}
	else
	{
		scoped_lock lock(m_mutex);
		std::map<uint32_t, timer_data*>::iterator iter = m_timer_map.find(tCurID);
		if (iter != m_timer_map.end())
		{
			timer_data* data = iter->second;
			if (data)
			{
				data->m_timer.expires_from_now(boost::posix_time::milliseconds(data->m_duration));
				data->m_timer.async_wait(boost::bind(&TimerManager::on_timer, this,
					boost::asio::placeholders::error, data));
			}
		}
	}
    
	return tCurID;
}

void TimerManager::cancel( TimerID tid )
{
    delete_timer(tid);
}

void TimerManager::on_timer( const boost::system::error_code &error, timer_data * data )
{
    if(!error)
    {
        if(data->m_handler)
        {
            data->m_handler(data->m_timer_id);
        }
    }
}

void TimerManager::delete_timer( TimerID id )
{
    scoped_lock lock(m_mutex);
    std::map<uint32_t, timer_data*>::iterator iterFind = m_timer_map.find(id);
    if(iterFind != m_timer_map.end())
    {
        delete iterFind->second;
        m_timer_map.erase(iterFind);
    }
}

void TimerManager::add_timer( TimerID id, uint32_t duration, const OnTimer & handler )
{
	if (m_pIOService)
	{
		scoped_lock lock(m_mutex);
		timer_data *data = new timer_data(*m_pIOService);
		data->m_duration = duration;
		data->m_handler = handler;
		data->m_timer_id = id;
		m_timer_map.insert(std::make_pair(id, data));
		data->m_timer.expires_from_now(boost::posix_time::milliseconds(data->m_duration));
		data->m_timer.async_wait(boost::bind(&TimerManager::on_timer, this,
			boost::asio::placeholders::error, data));
	}
}

void TimerManager::stop()
{
    for(std::map<uint32_t, timer_data*>::iterator iter = m_timer_map.begin();
        iter != m_timer_map.end(); ++iter)
    {
        delete iter->second;
    }
    m_timer_map.clear();
}

